package org.dromara.pe.service.impl;


import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.opencsv.CSVWriter;
import jakarta.servlet.http.HttpServletResponse;
import org.dromara.basic.domain.Member;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.pe.domain.DeviceScoreRaw;
import org.dromara.pe.domain.bo.DeviceScoreRawBo;
import org.dromara.pe.domain.bo.ScopeSettingBo;
import org.dromara.pe.domain.bo.TaskReservationBo;
import org.dromara.pe.domain.vo.*;
import org.dromara.pe.service.IScopeSettingService;
import org.dromara.pe.service.ITaskReservationService;
import org.dromara.utils.Utils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.dromara.pe.domain.bo.SportScoreBo;
import org.dromara.pe.domain.SportScore;
import org.dromara.pe.mapper.SportScoreMapper;
import org.dromara.pe.service.ISportScoreService;

import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 体测成绩管理Service业务层处理
 *
 * @author Lion Li
 * @date 2024-11-28
 */
@RequiredArgsConstructor
@Service
public class SportScoreServiceImpl implements ISportScoreService {

    private final SportScoreMapper baseMapper;

    private final IScopeSettingService iScopeSettingService;

    private final ITaskReservationService taskReservationService;

    /**
     * 查询体测成绩管理
     */
    @Override
    public SportScoreVo queryById(Long sportScoreId){
        return baseMapper.selectVoById(sportScoreId);
    }

    /**
     * 查询体测成绩管理列表
     */
    @Override
    public TableDataInfo<SportScoreVo> queryPageList(SportScoreBo bo, PageQuery pageQuery) {
        QueryWrapper<SportScore> lqw = buildQueryWrapper(bo);
        Page<SportScoreVo> result = baseMapper.selectSportScore(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询体测成绩管理列表
     */
    @Override
    public List<SportScoreVo> queryList(SportScoreBo bo) {
        QueryWrapper<SportScore> lqw = buildQueryWrapper(bo);
        return baseMapper.selectSportScore(lqw);
    }

    private QueryWrapper<SportScore> buildQueryWrapper(SportScoreBo bo) {
        Map<String, Object> params = bo.getParams();
        QueryWrapper<SportScore> lqw = new QueryWrapper<>();
        lqw.eq(bo.getTaskId() != null, "pptr.task_id", bo.getTaskId());
        lqw.eq(StringUtils.isNotBlank(bo.getStuNum()), "ppss.stu_num", bo.getStuNum());
        lqw.like(StringUtils.isNotBlank(bo.getStudentName()), "pmi.name", bo.getStudentName());
        lqw.eq(StringUtils.isNotBlank(bo.getGrade()), "pbtc.grade", bo.getGrade());
        lqw.eq(StringUtils.isNotBlank(bo.getGender()), "pmi.gender", bo.getGender());
        lqw.eq(StringUtils.isNotBlank(bo.getAcademicYear()), "peti.academic_year", bo.getAcademicYear());
        lqw.eq(StringUtils.isNotBlank(bo.getSemester()), "peti.semester", bo.getSemester());
        lqw.eq(bo.getFlag()!=null, "ppss.flag", bo.getFlag());
        lqw.eq(bo.getDeptId()!=null, "sd2.dept_id", bo.getDeptId());
        lqw.eq(bo.getClassId() != null, "pptr.class_id", bo.getClassId());
        lqw.eq(bo.getArrangeId() != null, "pptr.arrange_id", bo.getArrangeId());
        lqw.orderByAsc("ppss.stu_num");
        lqw.orderByAsc("pptr.class_id");
        return lqw;
    }
    private QueryWrapper<SportScoreBo> buildQueryWrapper2(SportScoreBo bo) {
        Map<String, Object> params = bo.getParams();
        QueryWrapper<SportScoreBo> lqw = new QueryWrapper<>();
        lqw.eq(StringUtils.isNotBlank(bo.getUid()), "pdsr.uid", bo.getUid());
        lqw.eq(StringUtils.isNotBlank(bo.getSportId()), "pdsr.sport_id", bo.getSportId());
        lqw.like(StringUtils.isNotBlank(bo.getStudentName()), "pdsr.name", bo.getStudentName());
        lqw.like(StringUtils.isNotBlank(bo.getSportName()), "pdsr.sport_name", bo.getSportName());
        lqw.eq(bo.getClassId() != null, "pmi.class_id", bo.getClassId());
        lqw.eq(bo.getTaskId() != null, "pptr.task_id", bo.getTaskId());
        lqw.eq(bo.getArrangeId() != null, "pptr.arrange_id", bo.getArrangeId());
        lqw.eq(bo.getClassId() != null, "pmi.class_id", bo.getClassId());
        lqw.eq(bo.getType() != null, "pdsr.type", bo.getType());
        lqw.eq(bo.getScoreType() != null, "pdsr.score_type", bo.getScoreType());
        lqw.eq(StringUtils.isNotBlank(bo.getAcademicYear()), "pdsr.stu_year", bo.getAcademicYear());
        lqw.eq(StringUtils.isNotBlank(bo.getLevel()), "pdsr.level", bo.getLevel());
        lqw.in(CollectionUtils.isNotEmpty(bo.getScoreTypes()) , "pdsr.score_type", bo.getScoreTypes());
        lqw.eq(bo.getScoreType()!=null, "pdsr.score_type", bo.getScoreType());
        if(StringUtils.isEmpty(bo.getOrderByColumn())){
            lqw.orderBy(true,false,"pdsr.completed_time");
        }else{
            lqw.orderBy(StringUtils.isNotEmpty(bo.getIsAsc()),"asc".equals(bo.getIsAsc()),"pdsr.completed_time");
        }
        lqw.orderBy(true,true,"pdsr.uid");
        lqw.between(params.get("beginCompletedTime") != null && params.get("endCompletedTime") != null,
            "pdsr.completed_time",params.get("beginCompletedTime"), params.get("endCompletedTime"));
        return lqw;
    }

    /**
     * 新增体测成绩管理
     */
    @Override
    public Boolean insertByBo(SportScoreBo bo) {
        SportScore add = MapstructUtils.convert(bo, SportScore.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setSportScoreId(add.getSportScoreId());
        }
        return flag;
    }

    /**
     * 修改体测成绩管理
     */
    @Override
    public Boolean updateByBo(SportScoreBo bo) {
        SportScore update = MapstructUtils.convert(bo, SportScore.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SportScore entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除体测成绩管理
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    public Boolean batchCreate(SportScoreBo bo){
        List<String>a=new ArrayList<>();
        a.add("E-2-1");
        bo.setSportIds(a);
        List<DeviceScoreRawVo> deviceScoreRawVos = baseMapper.selectAchievementList(this.buildQueryWrapper2(bo),bo);
        TaskReservationBo taskReservationBo=new TaskReservationBo();
        BeanUtils.copyProperties(bo, taskReservationBo);
        if(CollectionUtils.isEmpty(deviceScoreRawVos)){
            throw new ServiceException("无数据可同步");
        }
        Map<String, List<DeviceScoreRawVo>> studentIdMap = deviceScoreRawVos.stream()
            .collect(Collectors.groupingBy(DeviceScoreRawVo::getUid));
        List<ScopeSettingVo> scopeSettingVos = iScopeSettingService.queryList(new ScopeSettingBo());
        if(CollectionUtils.isEmpty(scopeSettingVos)){
            throw new ServiceException("请配置文件");
        }
        List<TaskReservationVo> taskReservationVos = taskReservationService.queryList(taskReservationBo);
        if(CollectionUtils.isEmpty(taskReservationVos)){
            throw new ServiceException("请先生成名单");
        }
        for(TaskReservationVo taskReservationVo:taskReservationVos){
            SportScore sportScoreBo=new SportScore();
            Map<String, ScoreDto> stringListMap = new HashMap<>();
            sportScoreBo.setStuNum(taskReservationVo.getStuNum());
            sportScoreBo.setTaskId(taskReservationVo.getTaskId());
            if(studentIdMap.containsKey(taskReservationVo.getStuNum())){
                for (DeviceScoreRawVo item : studentIdMap.get(taskReservationVo.getStuNum())) {
                    ScoreDto scoreDto=new ScoreDto();
                    scoreDto.setSportId(item.getSportId());
                    scoreDto.setSportName(item.getSportName());
                    if(item.getSportScore()!=null){
                        scoreDto.setSportRaw(item.getSportScore().toString());
                    }
                    if(item.getScore()!=null){
                        scoreDto.setSportScore(item.getScore().toString());
                    }
                    stringListMap.put(item.getSportId(),scoreDto);

                }
                sportScoreBo.setFlag(0L);
            }else {
                sportScoreBo.setFlag(1L);
            }
            for(ScopeSettingVo scopeSettingVo:scopeSettingVos){
                if(!stringListMap.containsKey(scopeSettingVo.getSportId())){
                    ScoreDto scoreDto=new ScoreDto();
                    scoreDto.setSportId(scopeSettingVo.getSportId());
                    scoreDto.setSportName(scopeSettingVo.getSportName());
                    stringListMap.put(scopeSettingVo.getSportId(),scoreDto);
                }
            }
            List<ScoreDto> scoreDtoList = stringListMap.values().stream()
                .sorted((dto1, dto2) -> dto1.getSportId().compareTo(dto2.getSportId()))
                .collect(Collectors.toList());
            if(CollectionUtils.isNotEmpty(scoreDtoList)){
                String jsonString = JsonUtils.toJsonString(scoreDtoList);
                sportScoreBo.setSportScore(jsonString);
            }
            if(sportScoreBo.getStuNum()!=null&&sportScoreBo.getTaskId()!=null){
                SportScoreVo sportScoreVo = this.querySportScore(sportScoreBo.getStuNum(), sportScoreBo.getTaskId());
                if(ObjectUtils.isNotEmpty(sportScoreVo)){
                    this.updateSportScore(sportScoreBo);
                }else {
                    baseMapper.insert(sportScoreBo);
                }
            }
        }
        return true;
    }
    private SportScoreVo querySportScore(String stuNum,Long taskId){
        return baseMapper.selectVoOne(
            new LambdaQueryWrapper<SportScore>()
                .eq(StringUtils.isNotEmpty(stuNum),SportScore::getStuNum,stuNum)
                .eq(taskId!=null,SportScore::getTaskId,taskId)

        );
    }
    private Boolean updateSportScore(SportScore sportScore){
        return baseMapper.update(sportScore,
            new LambdaQueryWrapper<SportScore>()
                .eq(StringUtils.isNotEmpty(sportScore.getStuNum()),SportScore::getStuNum,sportScore.getStuNum())
                .eq(sportScore.getTaskId()!=null,SportScore::getTaskId,sportScore.getTaskId())

        )>0;
    }
    public void exportScore(SportScoreBo bo, HttpServletResponse response){
        List<SportScoreVo> sportScoreVoList = this.queryList(new SportScoreBo());
        for(SportScoreVo scopeSettingVo:sportScoreVoList){
            if(StringUtils.isNotEmpty(scopeSettingVo.getSportScore())){
                List<ScoreDto> scoreDtos1 = JSON.parseArray(scopeSettingVo.getSportScore(), ScoreDto.class);
                scopeSettingVo.setScoreList(scoreDtos1);
            }
        }
        List<ScopeSettingVo> scopeSettingVos = iScopeSettingService.queryList(new ScopeSettingBo());
        List<String> header=new ArrayList<>();
        header.add("姓名");header.add("学号");header.add("班级");header.add("学院");
        header.add("年级");header.add("性别");

        for(ScopeSettingVo scopeSettingVo:scopeSettingVos){
            header.add(scopeSettingVo.getSportName()+"成绩");
            header.add(scopeSettingVo.getSportName()+"分数");
        }
        try (
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
             CSVWriter writer = new CSVWriter(outputStreamWriter)
          ) {
            // 写入表头
            writer.writeNext(header.stream().toArray(String[]::new));
            // 遍历外层数据列表
            for (SportScoreVo outerData : sportScoreVoList) {
                String studentName = outerData.getStudentName();
                String stuNum = outerData.getStuNum();
                String className = outerData.getClassName();
                String collegeName = outerData.getCollegeName();
                String grade = outerData.getGrade();
                String gender = outerData.getGender();

                // 处理内层数据列表
                List<ScoreDto> innerDataList = outerData.getScoreList();
                List<String> rowData2=new ArrayList<>();
                rowData2.add(studentName);
                rowData2.add(stuNum);
                rowData2.add(collegeName);
                rowData2.add(className);
                rowData2.add(grade);
                rowData2.add("0".equals(gender)?"男":"女");
                for(ScoreDto innerData:innerDataList){
                    rowData2.add(innerData.getSportRaw());
                    rowData2.add(innerData.getSportScore());
                }

                // 写入数据行
                writer.writeNext(rowData2.stream().toArray(String[]::new));

            }
            response.getOutputStream().flush();
            System.out.println("CSV 文件导出成功");
        } catch (IOException e) {
            System.out.println("导出 CSV 文件出错: " + e.getMessage());
        }
    }
    public void createScoreTemplate(TaskReservationBo taskReservationBo){
        List<TaskReservationVo> taskReservationVos = taskReservationService.queryList(taskReservationBo);
//        // 方案1
//        try (ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build()) {
//            WriteSheet writeSheet = EasyExcel.writerSheet().build();
//            FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build();
//            // 如果有多个list 模板上必须有{前缀.} 这里的前缀就是 data1，然后多个list必须用 FillWrapper包裹
//            excelWriter.fill(new FillWrapper("data1", data()), fillConfig, writeSheet);
//            excelWriter.fill(new FillWrapper("data1", data()), fillConfig, writeSheet);
//            excelWriter.fill(new FillWrapper("data2", data()), writeSheet);
//            excelWriter.fill(new FillWrapper("data2", data()), writeSheet);
//            excelWriter.fill(new FillWrapper("data3", data()), writeSheet);
//            excelWriter.fill(new FillWrapper("data3", data()), writeSheet);
//
//            Map<String, Object> map = new HashMap<String, Object>();
//            //map.put("date", "2019年10月9日13:28:28");
//            map.put("date", new Date());
//
//            excelWriter.fill(map, writeSheet);
//        }
//    }
    }
}
